package force;

import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.util.Scanner;
import object.mass.Mass;
import sim.Simulation;

/**
 * Represents a wall repulsion force. Has an
 * ID corresponding to one of the walls.
 * @author Niel Lebeck and Wynne Lok
 *
 */
public class WallForce extends GlobalForceSource {
    private static final int TOP_WALL = 0;
    private static final int RIGHT_WALL = 1;
    private static final int BOTTOM_WALL = 2;
    private static final int LEFT_WALL = 3;
    
    private static final int[] WALL_FORCE_DIR = {
        90, 180, 270, 0
    };
    
    private static final int LEFT_WALL_FORCE_DIR = 0;
    private static final int BOTTOM_WALL_FORCE_DIR = 270;
    private static final int RIGHT_WALL_FORCE_DIR = 180;
    private static final int TOP_WALL_FORCE_DIR = 90;
    
    private static final double DEFAULT_WALL_FORCE_MAG = 100000;
    private static final double DEFAULT_WALL_FORCE_EXP = 2;
    
    private boolean myWallForceOn;
    private double myWallForceMag;
    private double myWallForceExp;
    private int myWallForceId;
    
    /**
     * 
     * @param line String
     */
    public WallForce(String line) {
        Scanner s = new Scanner(line);
        String type = s.next();
        myWallForceId = s.nextInt() - 1;
        myWallForceMag = s.nextDouble();
        myWallForceExp = s.nextDouble();
        myWallForceOn = true;
    }
    
    /**
     * 
     * @param id the wall ID of this wall force
     */
    public WallForce(int id) {
        myWallForceId = id;
        myWallForceMag = DEFAULT_WALL_FORCE_MAG;
        myWallForceExp = DEFAULT_WALL_FORCE_EXP;
        myWallForceOn = false;
    }
    
    /**
     * Calculate the wall repulsion force on the given Mass.
     * @param m Mass
     * @param sim Simulation
     * @return
     */
    @Override
    public Force getForce (Mass m, Simulation sim) {
        Force result;
        if (myWallForceOn) {
            result = new Force(WALL_FORCE_DIR[myWallForceId],
                    myWallForceMag
                    / Math.pow(getWallDistance(m, sim), myWallForceExp));
        }
        else {
            result = new Force(0, 0);
        }
        return result;
    }

    @Override
    public void toggle(int keycode) {
        if ((keycode == KeyEvent.VK_1 && myWallForceId == TOP_WALL)
                || (keycode == KeyEvent.VK_2 && myWallForceId == RIGHT_WALL)
                || (keycode == KeyEvent.VK_3 && myWallForceId == BOTTOM_WALL)
                || (keycode == KeyEvent.VK_4 && myWallForceId == LEFT_WALL)) {
            myWallForceOn = !myWallForceOn;
        }
    }
    
    private double getWallDistance(Mass m, Simulation sim) {
        Point2D center = m.getCenter();
        switch (myWallForceId) {
            case LEFT_WALL:
                return center.getX();
            case TOP_WALL:
                return center.getY();
            case RIGHT_WALL:
                return sim.getSize().getWidth() - center.getX();
            case BOTTOM_WALL:
                return sim.getSize().getHeight() - center.getY();
            default:
                return 0.0;
        }
    }
}
